feat(spec-090): admin audit log view#4
Merged
hendrikebbers merged 6 commits intomainfrom Apr 26, 2026
Merged
Conversation
Link spec 090 to GitHub issue #3 and update status. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Includes a deviation note documenting why a project-local CrmAuditLogRepository is needed: AuditLogDataService in spring-services exposes only unpaginated filter methods, which would force in-memory pagination over the entire audit table. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds GET /api/audit-logs (paginated, optional entityType/user filters, sorted by createdAt DESC) and GET /api/audit-logs/entity-types (distinct entity-type values for the filter dropdown). Filtering uses a project-local CrmAuditLogRepository because AuditLogDataService in spring-services exposes only unpaginated filter methods (List<AuditLogDto>), which would force in-memory pagination over an unbounded audit table. Both endpoints are guarded by class-level @RequiresItAdmin. Adds 9 controller behaviour tests, 8 SecurityRoleIntegrationTest cases, and a PreAuthorizeAnnotationTest assertion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds /admin/audit-logs admin page (IT-ADMIN only) with: - Paginated table (Type, Entity ID, Action, User, Date) sorted by createdAt DESC - Two filter dropdowns: entity type (from GET /api/audit-logs/entity-types) and user (from existing GET /api/users, with the System user filtered out) - Page-size selector (10/20/50/100/200), persisted in localStorage under pageSize.auditLogs, default 20 - Loading / empty / error states; total-count display - Sidebar nav entry under the Admin sub-menu (FileText icon) Backend access control is inherited from the controller's class-level @RequiresItAdmin; the page also gates the route with ROLE_IT_ADMIN in the server component (ForbiddenPage fallback). Includes 19 Vitest component tests covering loading/empty/error states, table rendering with the System user, pagination, localStorage persistence, and dropdown population. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Extend "Admin Pages" feature description with the Users and Audit Log sub-pages, IT-ADMIN gating, and the audit log filter semantics (System entries only visible without a user filter). - Add backend auditlog/ package and admin/users/ + admin/audit-logs/ frontend directories to the project structure tree. - Fix two pre-existing UTF-8 corruption marks (U+FFFD) in the admin/token and admin/brevo lines while editing the section. - Mark Step 9 of steps.md as complete. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an
/admin/audit-logsadmin page (IT-ADMIN only) that lists every INSERT/UPDATE/DELETE event recorded by the platform's audit infrastructure. Entries are shown in a paginated, filterable table sorted bycreatedAtdescending. There is no detail view, no editing, no row-level actions.Spec
specs/090-audit-log-view/specs/090-audit-log-view/design.mdspecs/090-audit-log-view/behaviors.mdspecs/090-audit-log-view/steps.mdChanges
Backend
AuditLogControllerexposesGET /api/audit-logs(paginated, optionalentityType/userfilters, fixedcreatedAt DESCsort) andGET /api/audit-logs/entity-types(distinct values for the filter dropdown). Both endpoints are gated by class-level@RequiresItAdmin.CrmAuditLogRepositoryis a project-local Spring Data repository overAuditLogEntity(fromcom.open-elements:spring-services). It exists because the dependency'sAuditLogDataServiceexposes only unpaginatedList-returning filter methods, which would force in-memory pagination over an unbounded audit table. The fix preserves the design's contract (DB-layer pagination) without modifying the dependency.Frontend
app/(app)/admin/audit-logs/page.tsx— checksROLE_IT_ADMIN, falls back to<ForbiddenPage />.audit-logs-client.tsx— paginated table (Type / Entity ID / Action / User / Date), two filter dropdowns, page-size selector (10/20/50/100/200, persisted inlocalStorage["pageSize.auditLogs"], default 20), loading skeleton, empty state, error state. The user dropdown is populated fromgetUsers({ size: 200 })and excludes the syntheticSystemuser.FileTexticon).getAuditLogsandgetAuditLogEntityTypesinfrontend/src/lib/api.ts; newAuditLogDto/AuditActiontypes infrontend/src/lib/types.ts.nav.auditLogs+ fullauditLognamespace added to bothde.tsanden.ts.Documentation
project-features.mdandproject-structure.mdupdated. Two pre-existing UTF-8 corruption marks (U+FFFD) inproject-structure.mdwere repaired in the same edit.Deviation from
design.mdThe design referenced
auditLogDataService.findByEntityType(entityType, pageable)etc. The actualAuditLogDataServiceAPI only provides unpaginatedList-returning filter methods. The implementation introduces a small project-local repository to keep filtering at the DB layer; the endpoint contract, query parameters, and response payload are unchanged. The full reasoning is recorded at the top ofspecs/090-audit-log-view/steps.md.Test coverage
behaviors.mdmapped to tests in the coverage table at the top ofsteps.md.AuditLogControllerTest), 8 role-integration tests (SecurityRoleIntegrationTest), 1 annotation test (PreAuthorizeAnnotationTest). Full backend suite green: 58/58.AuditLogsClient(loading / empty / error / table rendering / System-user row / pagination defaults / localStorage persistence / page-size resets / dropdown population). All pass.<Select>popover content are not asserted via DOM events — same jsdom limitation accepted in spec 089's review. The filter logic itself is exercised by the backend filter tests for every parameter combination.Test plan
cd backend && ./mvnw verifycd frontend && pnpm test src/app/\(app\)/admin/audit-logs/__tests__/audit-logs-client.test.tsx/admin/audit-logsas an IT-ADMIN user and verify table content + filter behaviour against a populated audit log.ForbiddenPagewhen accessed without IT-ADMIN.Closes #3
🤖 Generated with Claude Code